#include "GLHeaders.hpp"
#include <cmath>
#include "Vector.hpp"

//Constructor
Vector::Vector(void){
	x = (GLfloat)0.0f;
	y = (GLfloat)0.0f;
	z = (GLfloat)0.0f;
}

Vector::Vector(const GLfloat fa){
	x = fa;
	y = fa;
	z = fa;
}

Vector::Vector(const GLfloat fx, const GLfloat fy, const GLfloat fz){
	x = fx;
	y = fy;
	z = fz;
}

Vector::Vector(const Vector& vector){
	x = vector.x;
	y = vector.y;
	z = vector.z;
}

//Arithmetic operations
Vector Vector::operator + () const{
	return Vector(*this);
}

Vector Vector::operator - () const{
	return Vector(
			-x,
			-y,
			-z);
}


Vector Vector::operator + (const Vector& rhs) const{
	return Vector(
			x+rhs.x,
			y+rhs.y,
			z+rhs.z);
}

Vector Vector::operator + (const GLfloat& value) const{
	return Vector(
			x+value,
			y+value,
			z+value);
}

Vector Vector::operator - (const Vector& rhs) const{
	return Vector(
			x-rhs.x,
			y-rhs.y,
			z-rhs.z);
}

Vector Vector::operator - (const GLfloat& value) const{
	return Vector(
			x-value,
			y-value,
			z-value);
}

Vector Vector::operator * (const Vector& rhs) const{
	return Vector(
			x*rhs.x,
			y*rhs.y,
			z*rhs.z);
}

Vector Vector::operator * (const GLfloat& value) const{
	return Vector(
			x*value,
			y*value,
			z*value);
}

Vector Vector::operator / (const Vector& rhs) const{
	return Vector(
			x/rhs.x,
			y/rhs.y,
			z/rhs.z);
}

Vector Vector::operator / (const GLfloat& value) const{
	return Vector(
			x/value,
			y/value,
			z/value);
}

Vector Vector::operator ^ (const Vector& rhs) const{
	return Vector(
			y*rhs.z-z*rhs.y,
			z*rhs.x-x*rhs.z,
			x*rhs.y-y*rhs.x);
}

//Friend Methods
Vector operator + (const GLfloat& value, const Vector& rhs){
	return Vector(
			value+rhs.x,
			value+rhs.y,
			value+rhs.z);
}

Vector operator - (const GLfloat& value, const Vector& rhs){
	return Vector(
			value-rhs.x,
			value-rhs.y,
			value-rhs.z);
}

Vector operator * (const GLfloat& value, const Vector& rhs){
	return Vector(
			value*rhs.x,
			value*rhs.y,
			value*rhs.z);
}

Vector operator / (const GLfloat& value, const Vector& rhs){
	return Vector(
			value/rhs.x,
			value/rhs.y,
			value/rhs.z);
}

//Boolean operation
bool Vector::operator < (const Vector& rhs) const{
	if((x < rhs.x) && (y < rhs.y) && (z < rhs.z))
		return true;
	else
		return false;
}

bool Vector::operator <= (const Vector& rhs) const{
	if((x <= rhs.x) && (y <= rhs.y) && (z <= rhs.z))
		return true;
	else
		return false;
}

bool Vector::operator == (const Vector& rhs) const{
	if((x == rhs.x) && (y == rhs.y) && (z == rhs.z))
		return true;
	else
		return false;
}  

bool Vector::operator != (const Vector& rhs) const{
	if((x != rhs.x) && (y != rhs.y) && (z != rhs.z))
		return true;
	else
		return false;
}

bool Vector::operator >= (const Vector& rhs) const{
	if((x >= rhs.x) && (y >= rhs.y) && (z >= rhs.z))
		return true;
	else
		return false;
}

bool Vector::operator > (const Vector& rhs) const{
	if((x > rhs.x) && (y > rhs.y) && (z > rhs.z))
		return true;
	else
		return false;
}

//Arithmetic updates
Vector& Vector::operator =  (const Vector& rhs){
	x = rhs.x;
	y = rhs.y;
	z = rhs.z;
	return *this;
}

Vector& Vector::operator =  (const GLfloat& value){
	x = value;
	y = value;
	z = value;
	return *this;
}

Vector& Vector::operator += (const Vector& rhs){
	x += rhs.x;
	y += rhs.y;
	z += rhs.z;
	return *this;
}

Vector& Vector::operator += (const GLfloat& value){
	x += value;
	y += value;
	z += value;
	return *this;
}

Vector& Vector::operator -= (const Vector& rhs){
	x -= rhs.x;
	y -= rhs.y;
	z -= rhs.z;
	return *this;
}

Vector& Vector::operator -= (const GLfloat& value){
	x -= value;
	y -= value;
	z -= value;
	return *this;
}

Vector& Vector::operator *= (const Vector& rhs){
	x *= rhs.x;
	y *= rhs.y;
	z *= rhs.z;
	return *this;
}

Vector& Vector::operator *= (const GLfloat& value){
	x *= value;
	y *= value;
	z *= value;
	return *this;
}

Vector& Vector::operator /= (const Vector& rhs){
	x /= rhs.x;
	y /= rhs.y;
	z /= rhs.z;
	return *this;
}

Vector& Vector::operator /= (const GLfloat& value){
	x /= value;
	y /= value;
	z /= value;
	return *this;
}

//Functions
GLfloat Vector::Length(void) const{
	return sqrtf(
			x*x+
			y*y+
			z*z);
}

Vector Vector::Normalize(void) const{
	GLfloat length = this->Length();
	if(length == 0.0f)
		return Vector(0.0f, 0.0f, 0.0f);
	return Vector(
			x/length,
			y/length,
			z/length);
}

void Vector::Copy2f(GLfloat* tab) const{
	*tab     = x;
	*(tab+1) = y;
}


void Vector::Copy3f(GLfloat* tab) const{
	*tab     = x;
	*(tab+1) = y;
	*(tab+2) = z;
}

void Vector::Copy4f(GLfloat* tab) const{
	*tab     = x;
	*(tab+1) = y;
	*(tab+2) = z;
	*(tab+3) = 1.0f;
}

//Special vector
const Vector Vector::ZERO( 0.0f, 0.0f, 0.0f);
const Vector Vector::ONES( 1.0f, 1.0f, 1.0f);
const Vector Vector::UNIT_X( 1.0f, 0.0f, 0.0f); 
const Vector Vector::UNIT_Y( 0.0f, 1.0f, 0.0f); 
const Vector Vector::UNIT_Z( 0.0f, 0.0f, 1.0f); 
const Vector Vector::NEGATIVE_UNIT_X(-1.0f, 0.0f, 0.0f); 
const Vector Vector::NEGATIVE_UNIT_Y( 0.0f,-1.0f, 0.0f); 
const Vector Vector::NEGATIVE_UNIT_Z( 0.0f, 0.0f,-1.0f); 
